/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1/commercial
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may use this file in compliance with the License.
 * Alternatively, if you can't copy with the License, namely if you do not
 * want to provide source code of your modifications to this file, you may
 * negotiate a commercial licence with the initial developer.
 * You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is COID.
 *
 * The Initial Developer of the Original Code is
 * PosAm.
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Brano Kemen
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */


#ifndef __COID_SERVER_LOGSTREAM__HEADER_FILE__
#define __COID_SERVER_LOGSTREAM__HEADER_FILE__

#include "coid/comm/binstream/txtstream.h"

namespace coid {

////////////////////////////////////////////////////////////////////////////////
///Stream class
class logstream : public txtstream
{
public:
    token text() const                              { return _buf; }
    void discard()                                  { _obj = UMAX32;  _buf.reset_write(); }
    bool has_message() const                        { return !_buf.is_empty(); }

    logstream& set( uint id, uchar msgclass, uchar verb, const token& shortname, const char* src )
    {
        _fin = 0;
        _cclass = msgclass;
        _cverb = verb;
        _wflags = 0;
        _obj = id;

        if( shortname.len() >= 8 )
            memcpy( _short, shortname.ptr(), 8 );
        else
        {
            memcpy( _short, shortname.ptr(), shortname.len() );
            _short[shortname.len()] = 0;
        }

        if(src)
            xstrncpy( _src, src, 4 );
        else
            _src[0] = _src[1] = _src[2] = _src[3] = '.';

        ::time( (time_t*)&_time );
        _buf.reset_write();
        return *this;
    }

    virtual opcd write( const void* p, type t )
    {/*
        if( t == binstream::type::t_temp_enable_separator )
        {
            temp_set_separator( *(char*)p );
            return 0;
        }
        
        if( shall_put_separator() )
        {
            token t = _buf;
            if( t.last_char() != ' '  &&  t.last_char() != 0 )
                _buf.write_raw( &_sep, 1 );
        }*/
        return txtstream::write( p, t );
    }
/*
    virtual opcd write_compound_ref (const void* p, uint& num, type t, t_stream_out str)
    {
        if( shall_put_separator() )
        {
            token t = _buf;
            if( t.last_char() != ' '  &&  t.last_char() != 0 )
                _buf.write_raw( &_sep, 1 );
        }
        return txtstream::write_compound_ref( p, num, t, str );
    }
*/
    virtual void flush()    { _sep = 0;  _fin = 1;  txtstream::flush(); }

    void temp_set_separator( char sep )     { _sep = sep; }

    bool is_final() const   { return _fin != 0; }
    void reset_final()      { _fin = 0; }

    friend binstream& operator << (binstream& out, const logstream& s)
    {
        out << s._cclass << s._cverb << s._wflags << s._obj;
        out.write_fixed_array_content(s._src, 4 );
        out << s._time << s._buf;
        out.write_fixed_array_content( s._short, 8 );
        return out;
    }

    friend binstream& operator >> (binstream& in, logstream& s)
    {
        in >> s._cclass >> s._cverb >> s._wflags >> s._obj;
        in.read_fixed_array_content( s._src, 4 );
        in >> s._time >> s._buf;
        in.read_fixed_array_content( s._short, 8 );
        s.assign (&s._buf);
        return in;
    }

    logstream& operator = (const logstream& src)
    {
        _cclass = src._cclass;
        _cverb = src._cverb;
        _wflags = src._wflags;
        _obj = src._obj;
        _sep = src._sep;
        memcpy( _short, src._short, 8 );
        //_short = src._short;
        xstrncpy( _src, src._src, 4 );
        _time = src._time;
        _buf = src._buf;
        return *this;
    }

    logstream () {
        _sep = 0;
        _obj = UMAX32;
        assign(&_buf);
    }

    ~logstream ()
    {
        assign (0);
    }


    bool shall_put_separator() const        { return _sep != 0; }

    uchar               _cclass;
    uchar               _cverb;
    ushort              _wflags;
    char                _src[4];
    uint                _obj;
    time_t              _time;
    char                _short[8];
    binstreambuf        _buf;
    char                _fin;
    char                _sep;
};

////////////////////////////////////////////////////////////////////////////////
///Log filter descriptor
struct FILTER_ENTRY
{
    dynarray<uint> _ids;       ///< id's to let through
    uint   _xclass;            ///< msg classes to let through, bit mask
    uint   _flags;
    long    _time;
    enum {
        xVERB                   = 0xff,
        fTO_TIME                = 0x0100,
        fHAS_ID                 = 0x0200,       ///< an id is contained within flags

        xID                     = 0xffff0000,
        rID                     = 16,
    };

    void set_id (uint id)           { _flags &= ~xID;  _flags |= fHAS_ID | (id << rID); }
    void set_verb (uchar v)         { _flags &= ~xVERB;  _flags |= v; }

    FILTER_ENTRY () { _flags = 0; _xclass=UMAX32; }
    FILTER_ENTRY (uint obj, uint xclass, uint minverb, uint time = UMAX32, bool totime = false)
    {
        *_ids.add(1) = obj;
        _xclass = xclass;
        _flags = minverb & xVERB;
        if (totime)  _flags |= fTO_TIME;
        _time = time;
    }

    FILTER_ENTRY (dynarray<uint> objs, uint xclass, uint minverb, uint time = UMAX32, bool totime = false)
    {
        _ids.takeover( objs );
        _xclass = xclass;
        _flags = minverb & xVERB;
        if (totime)  _flags |= fTO_TIME;
        _time = time;
    }

    int passes (const logstream& log) const
    {
        if (_time) {
            if ((_flags & fTO_TIME)  &&  log._time >= _time)  return 0;
            else if (!(_flags & fTO_TIME)  &&  log._time < _time)  return 0;
        }

        if (!(_xclass & (1 << log._cclass)))  return 0;
        if (log._cverb < (_flags & xVERB))  return 0;
        return 1;
    }


    friend binstream& operator << (binstream& out, const FILTER_ENTRY& s)
    {
        return out << s._ids << s._xclass << s._flags << s._time;
    }

    friend binstream& operator >> (binstream& in, FILTER_ENTRY& s)
    {
        return in >> s._ids >> s._xclass >> s._flags >> s._time;
    }
};


////////////////////////////////////////////////////////////////////////////////
struct tree_info
{
    enum {
        xCHANGE_TYPE                = 0xff000000,           ///< type mask
        fOP_THREAD                  = 0x80000000,           ///< thread op
        fOP_DELETE                  = 0x40000000,           ///< delete op

        CHANGE_SET_OBJECT           = 0,
        CHANGE_DEL_OBJECT           = fOP_DELETE,

        CHANGE_SET_THREAD           = fOP_THREAD,
        CHANGE_DEL_THREAD           = fOP_THREAD | fOP_DELETE,

        xCHANGE_ID                  = 0x00ffffff,
    };

    uint id;                        ///< change_type + refid
    uint pid;                       ///< parent id (for objects) or thread id
    charstr code;
    charstr name;

	uint get_id() const {return id & xCHANGE_ID;}
	uint get_type() const {return id & xCHANGE_TYPE;}

	void get_name( charstr & tmp, uint id2 ) {
		tmp = name; tmp << " [" << code << "]   /" << id2 << "/";
	}

    friend binstream& operator << (binstream& out, const tree_info& id)
    {
        if( id.id & fOP_DELETE )
            return out << id.id << id.pid;
        else
            return out << id.id << id.pid << id.code << id.name;
    }
    friend binstream& operator >> (binstream& in, tree_info& id)
    {
        in >> id.id >> id.pid;
        if( !(id.id & fOP_DELETE) )
            in >> id.code >> id.name;
        return in;
    }
};



} // namespace coid

#endif //__COID_SERVER_LOGSTREAM__HEADER_FILE__
